/**
 *******************************************************************************
 * @file  main.c
 * @brief Main program template.
 @verbatim
   Change Logs:
   Date             Author          Notes
   2020-06-30        CDT         First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by HDSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 */
/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "sdk_config.h"
/** driver*/
#include "hc32_ddl.h"
#include "SEGGER_RTT.h"
#include "gpio.hpp"
#include "intflash.hpp"
#include "rs485.hpp"
/** modules*/
#include "file.hpp"
#include "firmwaredownload.hpp"
#include "firmwareprogram.hpp"
#include "protocolmodbus.hpp"
/** app*/
#include "configapi.hpp"
///> 采用OTA方式升级代码，
#define CONFIG_DEFAULTVALUE_UPDATE_LIMIT					10

using namespace device;
using namespace protocols;
using namespace storage;
using namespace ota;

static intflash *mFlash;
static firmwaredownload *mFirmwaredownload;
static firmwareprogram *mFirmwareprogram;
static protocolmodbus *mPSend;
static protocolmodbus *mPRec;
static uint8_t mSendBuff[256];
static uint8_t mRecBuff[256];
static rs485 *mUart;

extern "C" void JumpToApplication(uint32_t uiAppAddr)
{
	__asm volatile(
		"   ldr r1,		=0xffffffff\n\r  	"
		"   ldr r2,		[r0,#4]\n\r  			"
		"   ldr r0,		[r0,0]\n\r  			"
		"   msr msp,  r0\n\r      			"
		"   mov lr,   r1\n\r      			"
		"   bx        r2\n\r      			");
}

static void RunApp2(void)
{
	volatile uint32_t i = APP_FLASH_ADDR;
	__disable_irq();
	JumpToApplication(i);
}

static bool WriteCallback_Specmd(uint8_t ucSlaveAddr, uint16_t tCommand, uint8_t *ucData, uint16_t usLen)
{
	switch(tCommand)
	{
		case 0x09:
			if(!mFirmwareprogram->Program())
			{
				return(false);
			}
			RunApp2();
			return(true);
		default:
			break;
	}
	return(false);
}

static bool BroadCastCallback(protocolmodbus *tprotocol)
{
	return(false);
}

static uint8_t RequestCallback_Report(uint8_t *ucData)
{
	ucData[0] = mTarget.tProductInfor.ucManufactoryId;
	ucData[1] = mTarget.tProductInfor.ucClass;
	ucData[2] = mTarget.tProductInfor.ucSerial;
	ucData[3] = mTarget.tProductInfor.ucPriSerial;
	ucData[4] = 0;
	ucData[5] = mTarget.tProductInfor.ucSoftwareSerial[0];
	ucData[6] = mTarget.tProductInfor.ucSoftwareSerial[1];
	ucData[7] = mTarget.tProductInfor.ucHardwareSerial[0];
	ucData[8] = mTarget.tProductInfor.ucHardwareSerial[1];
	for(uint8_t i = 0; i < 24; i++)
	{
		ucData[9 + i] = mTarget.tProductInfor.ucSN[i];
	}
	for(uint8_t i = 0; i < 12; i++)
	{
		ucData[33 + i * 2] = 0;
		ucData[33 + i * 2 + 1] = 0;
	}
	return(0x39);
}

static void AppInit(void)
{
	SystemUpdate();
	mFlash = new intflash();
	mFirmwaredownload = new firmwaredownload(mFlash);
	mFirmwareprogram = new firmwareprogram(mFlash);
	mFirmwareprogram->CheckSumEnable = true;
	mFirmwaredownload->CheckSumEnable = true;
	mFirmwaredownload->ReadPrgInfor();
	if(!firmwaredownload::PrgInforUseable(&mFirmwaredownload->FirmWareInfor))
	{
		RunApp2();
	}
	if(mFirmwaredownload->FirmWareInfor.uiNewVersion == mFirmwaredownload->FirmWareInfor.uiOldVersion)
	{
		RunApp2();
	}
	if(mFirmwaredownload->FirmWareInfor.uiUpdateCount <	CONFIG_DEFAULTVALUE_UPDATE_LIMIT)
	{
		mFirmwareprogram->Program();
		mFirmwaredownload->FirmWareInfor.uiUpdateCount++;
		mFirmwaredownload->UpDatePrgInfor();
		RunApp2();
	}
	file::Init(mFlash);
	ComConfigGet();
	FactoryConfigGet();
	
	mPSend = new protocolmodbus();
	mPRec = new protocolmodbus();
	mPRec->BroadCastAddr = 0xfa;
	mPRec->RegisteOtaInterface(mFirmwaredownload);
	mPRec->SpeOrderCallBack = WriteCallback_Specmd;
	mPRec->RequestReportDataCallBack = RequestCallback_Report;
	mPRec->BroadCastCallBack = BroadCastCallback;
	
	gpio::GpioPinTPDF tPort;
	tPort.GpioPort = APP_UART_DE_PORT;
	tPort.GpioPin = APP_UART_DE_PIN;
	mUart = new rs485(uart::UART_INSTANCE_3, mSendBuff, mRecBuff, 256, &tPort);
	mUart->BaudRate = mTarget.tComConfig.usBaud;
	mUart->Parity = uart::UART_PARITY_TYPE_EVEN;
	mUart->Open();
}

/**
 * @brief  Main function of template project
 * @param  None
 * @retval int32_t return value, if needed
 */
int32_t main(void)
{
	uint16_t len;
	AppInit();
	
	while(1)
	{
		len = mUart->Read(mRecBuff);
		if(len)
		{
			if(!mPRec->Unpack(mRecBuff, len))
			{
				continue;
			}
			if(mPRec->SlaveAddr != mTarget.tComConfig.usAddr)
			{
				continue;
			}
			if(mPRec->Map(mPSend, mTarget.tComConfig.usAddr))
			{
				mPSend->SlaveAddr = mPRec->SlaveAddr;
				len = mPSend->Pack(mSendBuff);
				mUart->Write(mSendBuff, len);
			}
		}
	}
}

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
